/*
 * 基本功能，细节需要配合不同项目，不同实现。
 * */

import axios, { AxiosRequestConfig } from 'axios';
import { getLocalI18n } from '@/locales';
import asyncErrorHandle from './asyncErrorHandle';
import { getEnv } from '../index';

export const usercenter = '/usercenter';
export const manageCenter = '/manage-center';
export const dataModelWeb = '/data-model-web/web';
export const dataStandardsWeb = '/data-standards-web';
export const dataSecurity = '/security';
export const dataQuality = '/dataquality';
export const metadata = '/metadata';

// const win: any = window;
const isDev = getEnv() === 'dev';

// http请求拦截器
axios.interceptors.request.use(
  (config: any) => {
    if (config.method.toUpperCase() === 'GET') {
      config.url = config.url.indexOf('?') > 0
        ? `${config.url}&clearCache=${new Date().valueOf()}`
        : `${config.url}?clearCache=${new Date().valueOf()}`;
    }
    if (config.method.toUpperCase() === 'POST') {
      if (!config.headers['Content-Type']) {
        config.headers['Content-Type'] = 'application/json';
      }
    }

    config.headers['x-requested-with'] = 'XMLHttpRequest';

    // token相关操作
    return config;
  },
  (error: any) => Promise.reject(error)
);

const responseCallback = (data: any, skipError?: boolean, skipRefresh?: boolean) => {
  const intl = getLocalI18n();
  if (
    data.headers['content-type']
    && data.headers['content-type'].toLowerCase().includes('application/json')
  ) {
    const { code: _code, msg } = data.data;
    const code = +_code || _code;
    if (code === 200) {
      return data.data;
    }
    if (code === 401) {
      if (!isDev && !skipRefresh) {
        window.location.reload();
      }

      return null;
    }
    if (code === -200) {
      if (!skipError) {
        asyncErrorHandle(msg || intl('ajax.message.serviceException'));
      }

      return Promise.reject({
        response: {
          code,
          message: msg || '服务异常',
        },
      });
    }
    if (msg && !skipError) {
      asyncErrorHandle(msg);

      return Promise.reject({
        response: {
          code,
          message: msg,
        },
      });
    }

    return data.data;
  }
  if (
    data.config.responseType === 'arraybuffer'
    && data.headers['content-type'].indexOf('application/vnd.openxml') > -1
  ) {
    // 响应为二进制流的判断,即下载文件时候
    return data;
  }
  if (data.headers['content-type'].toLowerCase().indexOf('application/vnd.ms-excel') > -1) {
    return data;
  }

  return Promise.reject(new Error('请先登录'));
};

const errorCallback = (err: any, skipError?: boolean, skipRefresh?: boolean) => {
  const intl = getLocalI18n();

  const response = err?.response;
  if (response) {
    switch (response.status) {
      case 400:
        err.message = intl('ajax.message.requestError');
        break;
      case 303:
      case 302:
      case 307: {
        if (!isDev && !skipRefresh) {
          window.location.reload();
        }
        break;
      }
      case 401:
      case 420:
        err.message = null;
        if (!isDev && !skipRefresh) {
          window.location.reload();
        }
        if (response.data?.code !== 402) {
          // 做什么
        }
        break;
      case 403:
        err.message = intl('ajax.message.accessDenied');
        // window.location.hash = "#/notAuth";
        break;
      case 404:
        err.message = `${intl('ajax.message.errorRequestingAddress')}: ${response.config?.url}`;
        break;
      case 408:
        err.message = intl('ajax.message.requestTimeout');
        break;
      case 500:
        err.message = intl('ajax.message.serverInternalError');
        break;
      case 501:
        err.message = intl('ajax.message.serviceNotImplemented');
        break;
      case 502:
        err.message = intl('ajax.message.badGateway');
        break;
      case 503:
        err.message = intl('ajax.message.serviceUnavailable');
        break;
      case 504:
        err.message = intl('ajax.message.gatewayTimeout');
        break;
      case 505:
        err.message = intl('ajax.message.theHTTPVersionIsNotSupported');
        break;
      default:
    }
    if (err.message && !skipError) {
      asyncErrorHandle(err.message);
    }

    return Promise.reject(err);
  }

  if (!isDev && !skipRefresh) {
    window.location.reload();
  }

  return Promise.reject(err);
};

type AxiosInst = typeof axios & {
  upload: (url: string, params: any) => Promise<any>;
};

const axiosAlis = axios as AxiosInst;

// 上传接口
axiosAlis.upload = (url: string, params: any) =>
  axios.post(url, params, {
    transformRequest: [data => toFormData(data)],
    headers: { 'Content-Type': 'multipart/form-data' },
  });

export const toFormData = (data: any) => {
  const formData = new FormData();
  if (!data) {
    return formData;
  }
  Object.keys(data).forEach(key => {
    const value = data[key];
    if (value !== undefined) {
      formData.append(key, data[key]);
    }
  });

  return formData;
};

type RequestConfg = AxiosRequestConfig & {
  skipError?: boolean;
  skipRefresh?: boolean;
};

const request = (config: RequestConfg) => {
  const { skipError, skipRefresh } = config;

  return axiosAlis(config)
    .then(resp => responseCallback(resp, skipError, skipRefresh))
    .catch(err => errorCallback(err, skipError, skipRefresh));
};

const instFun = (config: RequestConfg) => request(config);

const inst = {
  upload: axiosAlis.upload,
  get: (url: string, config?: RequestConfg) => request({ ...config, url, method: 'GET' }),
  post: (url: string, data?: any, config?: RequestConfg) =>
    request({
      ...config,
      url,
      method: 'POST',
      data,
    }),
  put: (url: string, data?: any, config?: RequestConfg) =>
    request({
      ...config,
      url,
      method: 'PUT',
      data,
    }),
  delete: (url: string, config?: RequestConfg) => request({ ...config, url, method: 'DELETE' }),
  options: (url: string, config?: RequestConfg) => request({ ...config, url, method: 'OPTIONS' }),
  patch: (url: string, config?: RequestConfg) => request({ ...config, url, method: 'PATCH' }),
  head: (url: string, config?: RequestConfg) => request({ ...config, url, method: 'HEAD' }),
};

export default Object.assign(instFun, inst);
